import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;

// TODO change servername and password

public class HeatPanel extends JPanel implements TLModule
{
	int limit = 30; // number of songs to be loaded
	
	private final int LENGTH = 100;// length of the heat map
	private Framework fw;
	private int maxNr = 200;
	private int levelNUM = 20;
	public JLabel[] songLabels;
	public JCheckBox[] checkBoxs;
	public CustomJList[] heatLists;
	public List<String> songNames;
	public ArrayList<ArrayList<Integer>> heats = new ArrayList<ArrayList<Integer>>();
	public List<Long> songIDs;
	public ArrayList<ArrayList<Long>> phraseIDs =new ArrayList<ArrayList<Long>>();
	public ColorPool colorPool;
	
	public HeatPanel(Framework in_fw)
	{
		fw = in_fw;
		reset();		
	}
	
	private void setComponents(){
		// initialize components
		songLabels = new JLabel[songNames.size()];
		checkBoxs = new JCheckBox[songNames.size()];
		heatLists = new CustomJList[songNames.size()];
		
		Container jp = new Container();
		colorPool = new ColorPool();
		ColorRenderer cellRenderer = new ColorRenderer();
		
		// set layout
		GridBagLayout layout = new GridBagLayout();
		jp.setLayout(layout);
		// set width
		GridBagConstraints a = new GridBagConstraints();
		GridBagConstraints b = new GridBagConstraints();
		GridBagConstraints c = new GridBagConstraints();
		
		// add components to layout
		for (int i=0;i<songNames.size();i++){
			a.gridy ++;
			b.gridy ++;
			c.gridy ++;
			songLabels[i] = new JLabel(songNames.get(i));
			songLabels[i].setFont(new Font("serif",Font.PLAIN,10));
			songLabels[i].setHorizontalTextPosition(JLabel.RIGHT);
			songLabels[i].setPreferredSize(new Dimension(70,10));
			checkBoxs[i] = new JCheckBox();
			checkBoxs[i].setPreferredSize(new Dimension(20,10));
			heatLists[i] = new CustomJList(colorPool,heats.get(i));
			songLabels[i].setHorizontalTextPosition(JLabel.RIGHT);
			heatLists[i].setCellRenderer(cellRenderer);
			jp.add(songLabels[i],a);
			jp.add(heatLists[i],b);
			jp.add(checkBoxs[i],c);
		}
		JScrollPane js = new JScrollPane(jp);
		add(js);
		
		ListSelectionListener listListener = new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent e) {
				if   (!e.getValueIsAdjusting())   { 
					ArrayList<Long> selectedPhrases = new ArrayList<Long>();
	                int c = e.getFirstIndex();
	                int r;
	                for (r=0;r<heatLists.length;r++){
	                	if (heatLists[r].equals((e.getSource()))){
	                		selectedPhrases.add(phraseIDs.get(r).get(c));
	                		break;
	                	}
	                }
	                System.out.print(selectedPhrases.get(0));
	                System.out.print(";");
	                System.out.println(selectedPhrases.size());
	                fw.resetPhrase();
					fw.resetSong();
					fw.highlightPhrase(selectedPhrases);
				}
			}
		};
		
		// add heatLists Listener
		int i;
		for (i=0;i<heatLists.length;i++){
			heatLists[i].addListSelectionListener(listListener);
		}
	
		// set checkBox listener
		MouseListener mouseListener = new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				int i;
				ArrayList<Long> selectedSongs = new ArrayList<Long>();
				for (i=0;i<checkBoxs.length;i++){
					if (checkBoxs[i].isSelected()){
						selectedSongs.add(songIDs.get(i));
					}
				}
				fw.resetPhrase();
				fw.resetSong();
				fw.highlightSong(selectedSongs);
			}
		};
		
		// add checkBox Listener
		int j;
		for (j=0;j<checkBoxs.length;j++){
			checkBoxs[j].addMouseListener(mouseListener);
		}
		this.setBackground(Color.WHITE);
				
	}

	private class ColorPool{
		private int alphaMin = 55;
		private int alphaMax = 255;
		private int stepSize;
		private int levelPerColor;
		private int index;
		public Color[] colorPool = new Color[levelNUM];

		public ColorPool() {
			this.levelPerColor = levelNUM / 2;
			this.stepSize = ((this.alphaMax - this.alphaMin) / this.levelPerColor);
		}

		public Color[] getColorPool()
		{
			this.index = 0;
			for (int alpha = this.alphaMax; alpha > this.alphaMin; alpha -= this.stepSize) {
				Color color = new Color(255, 0, 0, alpha);
				this.colorPool[this.index] = color;
				this.index += 1;
			}

			for (int alpha = this.alphaMin; alpha < this.alphaMax; alpha += this.stepSize) {
				Color color = new Color(0, 0, 100, alpha);
				this.colorPool[this.index] = color;
				this.index += 1;
			}
			return this.colorPool;
		}
	}
	
	public class CustomJList extends JList
	{	
		private final int cellHeight = 10;
		private int cellWidth;
		private Color[] colorMap;

		public CustomJList(ColorPool colorPool, List<Integer> songHeat)
		{
			colorMap = getColorMap(colorPool.getColorPool(),songHeat);
			setModel(getModel(colorMap));
			setFixedCellWidth(cellWidth);
			setFixedCellHeight(cellHeight);
			setLayoutOrientation(2);
			setVisibleRowCount(1);
			setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		}

		private ListModel getModel(Color[] colorMap) {
			DefaultListModel colorModel = new DefaultListModel();
			for (Color c : colorMap) {
				colorModel.addElement(c);
			}
			return colorModel;
		}

		private Color[] getColorMap(Color[] colorPool,List<Integer> songHeat) {
			colorMap = new Color[songHeat.size()];
			cellWidth = (LENGTH / songHeat.size());
			int i;
			for (i=0;i<songHeat.size();i++) {
				double songHeatValue = songHeat.get(i).doubleValue();
				int idx = (int) Math.floor(songHeatValue / maxNr * levelNUM);
				if (idx >= levelNUM){
					idx = levelNUM - 1;
				}
				idx = levelNUM - 1 - idx;  
				colorMap[i] = colorPool[idx];
			}
			return colorMap;
		}
	}
	
	public class ColorRenderer extends DefaultListCellRenderer
	{
		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
		{
			super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
			Color color = (Color)value;
			setText("");
			setBackground(color);
			return this;
		}
	}
	
	public void connectDatabase(){
		Connection connection = null;
        try {
        	// Load the JDBC driver
        	String driverName = "org.gjt.mm.mysql.Driver"; // MySQL MM JDBC driver
        	Class.forName(driverName);

	        // Create a connection to the database
	        String serverName = "localhost";
	        String mydatabase = "infviz";
	        String url = "jdbc:mysql://" + serverName + "/" + mydatabase; // a JDBC url
	        String username = "root";
	        String password = "augmented";
	        connection = DriverManager.getConnection(url, username, password);
        	} 
        catch (ClassNotFoundException e) {
	        // Could not find the database driver
	        } 
        catch (SQLException e) {
	        // Could not connect to the database
	        } 
		QueryRunner qr = new QueryRunner();
		ResultSetHandler rsh = new ColumnListHandler();
		ResultSetHandler rsh2 = new MapListHandler();
        
        String sql1= "SELECT song_id FROM song " +
        		"JOIN ranking " +
        		"USING(song_title) " +
        		"WHERE chart_name='hot-100' AND chart_date='2010-05-15' " +
        		"ORDER BY ranking "+
        		"LIMIT 0," + limit;
        String sql2 = "SELECT song_title FROM ranking " +
			"WHERE chart_date = '2010-05-15' and chart_name = 'hot-100' " +
			"ORDER BY ranking "+
			"LIMIT 0," + limit;
        
		try {
			songNames = (List<String>) qr.query(connection, sql2, rsh);
			songIDs = (List<Long>) qr.query(connection, sql1,rsh);
			for (String songTitle:songNames){
				StringBuffer sb = new StringBuffer(songTitle);
				int idx = sb.indexOf("'");
				if (idx > -1){
					sb.insert(idx, "\\");
				}
				int idx2 = sb.indexOf("(");
				if (idx2 > -1){
					sb.deleteCharAt(idx2);
				}
				int idx3 = sb.indexOf("(");
				if (idx3 > -1){
					sb.deleteCharAt(idx3);
				}
				
				String sql3 = "SELECT phrase_id, SUM(nr_tweets) " +
						"FROM lyrics " +
						"JOIN phrase_popularity " +
						"USING (phrase_id) " +
						"WHERE song_title = '" + sb.toString() + "' " +
						"GROUP BY phrase_id ORDER BY line_nr ";
				
				List<Map> bla = (List<Map>) qr.query(connection, sql3, rsh2);
					
				int j;
				ArrayList<Long> tempPr = new ArrayList<Long>();
				ArrayList<Integer> tempNr = new ArrayList<Integer>();
				for (j=0;j<bla.size();j++){
					Integer k = new Integer(bla.get(j).get("SUM(nr_tweets)").toString());
					if (k == null)
						tempNr.add(new Integer(0));
					else
						tempNr.add(k);
					
					tempPr.add((Long) bla.get(j).get("phrase_id"));
					}
				if (tempNr.size()==0)
					tempNr.add(new Integer(0));
				heats.add(tempNr);
				phraseIDs.add(tempPr);
			}
			
			
		} 
		catch (SQLException e) {
			e.printStackTrace();
		}		
	}

	@Override
	public void highlightPhrase(List<Long> phraseId) {
//		System.out.print(phraseId.size());
//		for (Long p:phraseId){
//			int row;
//			for (row=0;row<phraseIDs.size();row++){
//				int c = phraseIDs.get(row).indexOf(p);
//				if (c > 0){
//					heatLists[row].addSelectionInterval(c, c);
//				}
//			}
//		}
	}

	@Override
	public void highlightSong(List<Long> songId) {
		
		for (Long l:songId){
			int idx = songIDs.indexOf(l);
			if (idx == -1){
				break;
			}
			checkBoxs[idx].setSelected(true);
		}
	}

	@Override
	public void highlightUser(List<String> users) {
	}

	@Override
	public void reset() {
		connectDatabase();
		setComponents();
	}		

	@Override
	public void resetPhrase() {
//		int i;
//		for (i=0;i<heatLists.length;i++){
//			heatLists[i].clearSelection();
//		}
	}

	@Override
	public void resetSong() {
		int i;
		for (i=0;i<checkBoxs.length;i++){
			checkBoxs[i].setSelected(false);
		}
	}

	@Override
	public void resetTime() {
	}

	@Override
	public void resetUser() {	
	}

	@Override
	public void setPhrase(List<Long> phraseId) {
	}

	@Override
	public void setSong(List<Long> songId) {
	}

	@Override
	public void setTimeSpan(Timestamp start, Timestamp end) {
	}

	@Override
	public void setUser(List<String> users) {
	}

	@Override
	public void resetBillBoard(String chartName) {
		
	}

	@Override
	public void setBillBoard(String chartName) {
		
	}
	
}